# Copyright (C) 2025 Kumo inc.
# Author: Jeff.li lijippy@163.com
# All rights reserved.
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU Affero General Public License as published
# by the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Affero General Public License for more details.
#
# You should have received a copy of the GNU Affero General Public License
# along with this program.  If not, see <https:#www.gnu.org/licenses/>.
#
# distutils: language = c++

from status cimport CStatus
from libcpp.string cimport string as c_string
from libcpp.memory cimport unique_ptr
from libcpp.utility cimport move

cpdef public enum StatusCode:
    Ok = <int>CStatusCode.kOk,
    Cancelled = <int>CStatusCode.kCancelled,
    Unknown = <int>CStatusCode.kUnknown,
    InvalidArgument = <int>CStatusCode.kInvalidArgument,
    DeadlineExceeded = <int>CStatusCode.kDeadlineExceeded,
    NotFound = <int>CStatusCode.kNotFound,
    AlreadyExists = <int>CStatusCode.kAlreadyExists,
    PermissionDenied = <int>CStatusCode.kPermissionDenied,
    ResourceExhausted = <int>CStatusCode.kResourceExhausted,
    FailedPrecondition = <int>CStatusCode.kFailedPrecondition,
    Aborted = <int>CStatusCode.kAborted,
    OutOfRange = <int>CStatusCode.kOutOfRange,
    Unimplemented = <int>CStatusCode.kUnimplemented,
    Internal = <int>CStatusCode.kInternal,
    Unavailable = <int>CStatusCode.kUnavailable,
    DataLoss = <int>CStatusCode.kDataLoss,
    Unauthenticated = <int>CStatusCode.kUnauthenticated,
    IOError = <int>CStatusCode.kIOError

cdef extern from "turbopy/status_wrap.h":
    cdef CStatus *get_ok_status();

    cdef CStatus *get_status(int code, const c_string &);


cdef c_string _py_to_cpp_str(object py_data) except*:
    if isinstance(py_data, bytes):
        return <c_string> ((<bytes> py_data))
    elif isinstance(py_data, str):
        return <c_string> ((<str> py_data).encode('utf-8'))
    else:
        raise TypeError("must input str or bytes type")

cdef class Status:
    cdef unique_ptr[CStatus] c_status

    def __cinit__(self, StatusCode code, str message):
        if code == StatusCode.Ok:
            self.c_status.reset(get_ok_status())
        else:
            self.c_status.reset(get_status(<int> code, _py_to_cpp_str(message)))

    cpdef ok(self):
        return self.c_status.get().ok()

    cpdef code(self):
        return <int> self.c_status.get().code()

    cpdef message(self):
        return self.c_status.get().message()

    cpdef to_string(self):
        return self.c_status.get().to_string()

    cdef Status __assign__(self, Status other):
        if other is not None:
            self.c_status.reset(move(other.c_status).release())  # 转移所有权
        return self

    cpdef is_error_of(self, StatusCode code):
        return <int> self.c_status.get().code() == code

    cpdef is_aborted(self):
        return self.is_error_of(StatusCode.Aborted)

    cpdef is_already_exists(self):
        return self.is_error_of(StatusCode.AlreadyExists)

    cpdef is_cancelled(self):
        return self.is_error_of(StatusCode.Cancelled)

    cpdef is_data_loss(self):
        return self.is_error_of(StatusCode.DataLoss)

    cpdef is_deadline_exceeded(self):
        return self.is_error_of(StatusCode.DeadlineExceeded)

    cpdef is_failed_precondition(self):
        return self.is_error_of(StatusCode.FailedPrecondition)

    cpdef is_internal(self):
        return self.is_error_of(StatusCode.Internal)

    cpdef is_invalid_argument(self):
        return self.is_error_of(StatusCode.InvalidArgument)

    cpdef is_not_found(self):
        return self.is_error_of(StatusCode.NotFound)

    cpdef is_out_of_range(self):
        return self.is_error_of(StatusCode.OutOfRange)

    cpdef is_permission_denied(self):
        return self.is_error_of(StatusCode.PermissionDenied)

    cpdef is_resource_exhausted(self):
        return self.is_error_of(StatusCode.ResourceExhausted)

    cpdef is_unauthenticated(self):
        return self.is_error_of(StatusCode.Unauthenticated)

    cpdef is_unavailable(self):
        return self.is_error_of(StatusCode.Unavailable)

    cpdef is_unimplemented(self):
        return self.is_error_of(StatusCode.Unimplemented)

    cpdef is_unknown(self):
        return self.is_error_of(StatusCode.Unknown)

    cpdef is_io_error(self):
        return self.is_error_of(StatusCode.IOError)

cpdef aborted_status(str message):
    return Status(StatusCode.Aborted, message)

cpdef already_exists_status(str message):
    return Status(StatusCode.AlreadyExists, message)

cpdef cancelled_status(str message):
    return Status(StatusCode.Cancelled, message)

cpdef data_loss_status(str message):
    return Status(StatusCode.DataLoss, message)

cpdef deadline_exceeded_status(str message):
    return Status(StatusCode.DeadlineExceeded, message)

cpdef failed_precondition_status(str message):
    return Status(StatusCode.FailedPrecondition, message)

cpdef internal_status(str message):
    return Status(StatusCode.Internal, message)

cpdef invalid_argument_status(str message):
    return Status(StatusCode.InvalidArgument, message)

cpdef not_found_status(str message):
    return Status(StatusCode.NotFound, message)

cpdef out_of_range_status(str message):
    return Status(StatusCode.OutOfRange, message)

cpdef permission_denied_status(str message):
    return Status(StatusCode.PermissionDenied, message)

cpdef resource_exhausted_status(str message):
    return Status(StatusCode.ResourceExhausted, message)

cpdef unauthenticated_status(str message):
    return Status(StatusCode.Unauthenticated, message)

cpdef unavailable_status(str message):
    return Status(StatusCode.Unavailable, message)

cpdef unimplemented_status(str message):
    return Status(StatusCode.Unimplemented, message)

cpdef unknown_status(str message):
    return Status(StatusCode.Unknown, message)

cpdef io_error_status(str message):
    return Status(StatusCode.IOError, message)
